//
// Created by cube on 2020/9/12.
//

#ifndef COMPILERDOMEA1_BUFFER_H
#define COMPILERDOMEA1_BUFFER_H

#include <vector>
#include <iostream>

namespace NetBaseCommon {

    class Buffer {
    public:
        virtual uint32_t write(int8_t *data, const uint32_t &len) {return 0;};

        virtual uint32_t read(int8_t *data, const uint32_t &len) { return 0; };

        virtual uint32_t peek(int8_t *data, const uint32_t &len) { return 0; };

        virtual void clean() {}

        virtual std::size_t size() const { return 0; };

        virtual bool empty() const { return size() == 0; }

        virtual std::size_t maxSize() const {return UINT64_MAX;}
    };

    class IndexBuffer : public Buffer {
    public:
        IndexBuffer(const std::size_t& max_size) : __read_index(0),__max_size(max_size) {}

        uint32_t write(int8_t *data, const uint32_t &len) override {
            if (len > writeBufSize()) {
                compact();
                if(__buf.size() >= maxSize())return 0;
                if (len > writeBufSize()){
                    std::size_t size= __buf.size() + len;
                    if(size > maxSize())size = maxSize();
                    reserve(size);
                    size = writeBufSize();
                    for (int i = 0; i < size; i++)__buf.push_back(data[i]);
                    return size;
                }
            }
            for (int i = 0; i < len; i++)__buf.push_back(data[i]);
            return len;
        }

        uint32_t read(int8_t *data, const uint32_t &len) override {
            const uint32_t &_size = peek(data, len);
            __read_index += _size;
            if (__read_index > __buf.size())__read_index = __buf.size();
            return _size;
        }

        uint32_t peek(int8_t *data, const uint32_t &len) override {
            int rul_size = 0;
            for (rul_size = __read_index;
                 rul_size < size() && rul_size < len; rul_size++)
                *(data + rul_size) = __buf[rul_size];
            return rul_size;
        }

        void clean() override {
            __buf.clear();
            __read_index = 0;
        }


        std::size_t capacity() const { return __buf.capacity(); }

        std::size_t size() const override { return __buf.size() - __read_index; }

        std::size_t maxSize() const override { return __max_size; }

        void compact() {
            if (__read_index == 0)return;
            std::copy(__buf.begin() + __read_index, __buf.end(), __buf.begin());
            __buf.erase(__buf.begin() + __buf.size() - __read_index, __buf.end());
            __read_index = 0;
        }

        void reserve(const uint64_t &size) { __buf.reserve(size); }

    protected:
        std::size_t freeSize() {
            return writeBufSize() + __read_index;
        }

        std::size_t writeBufSize() {
            return __buf.capacity() - __buf.size();
        }

    private:
        const std::size_t& __max_size;
        std::size_t __read_index;
        std::vector<int8_t> __buf;
    };
}



#endif //COMPILERDOMEA1_BUFFER_H
